package com.backend.server.service.impl;

import com.backend.server.service.UserInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.server.common.ErrorCode;
import com.common.server.constant.UserConstant;
import com.common.server.entity.user.UserInfo;
import com.common.server.entity.user.vo.LoginUserInfoVO;
import com.common.server.entity.user.vo.UserInfoVO;
import com.common.server.exception.BusinessException;
import com.common.server.exception.ThrowUtils;
import com.common.server.mapper.UserInfoMapper;
import com.common.server.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.common.server.constant.UserConstant.SALT;

/**
 * @author Lenovo
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2024-12-26 13:23:51
 */
@Service
@Slf4j
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
        implements UserInfoService {
    @Resource
    private JwtUtil jwtUtil;
    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword) {
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请输入注册用户信息");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短, 长度至少4个字符");
        }
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短, 长度至少8个字符");
        }

        // 密码和校验密码相同
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
        }

        synchronized (userAccount.intern()) {
            // 账户不能重复
            QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_account", userAccount);
            long count = this.baseMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "该用户(账号)已存在, 请重新输入");
            }
            // 2. 加密
            String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
            // 3. 插入数据
            UserInfo userInfo = new UserInfo();
            userInfo.setUserAccount(userAccount);
            userInfo.setUserPassword(encryptPassword);
            boolean saveResult = this.save(userInfo);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "系统保存数据有误, 注册失败");
            }

            return userInfo.getId();
        }
    }

    @Override
    public Map<String, Object> userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "请输入登录用户信息");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误, 长度至少为4个字符");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误, 长度至少为8个字符");
        }

        // 2. 加密
        String encryptPassword = DigestUtils.md5DigestAsHex((UserConstant.SALT + userPassword).getBytes());
        // 查询用户是否存在
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        queryWrapper.eq("user_password", encryptPassword);
        UserInfo userInfo = this.baseMapper.selectOne(queryWrapper);
        // 用户不存在
        if (userInfo == null) {
            log.error("用户不存在或密码错误");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        // 3. 记录用户的登录态
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, userInfo);
        // 4.生成并返回 Token
        String token = jwtUtil.createToken(userInfo.getId().toString(), userInfo.getUserRole());
        LoginUserInfoVO loginUserVO = this.getLoginUserVO(userInfo);
        Map<String, Object> final_map = new HashMap<>();
        final_map.put("token", token);
        final_map.put("user", loginUserVO);
        return final_map;
    }

    /**
     * 用户注销
     *
     * @param request
     */
    @Override
    public boolean userLogout(HttpServletRequest request) {
        if (request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE) == null) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "用户未登录");
        }
        // 移除登录态
        request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        return true;
    }

    /**
     * 获取当前登录用户
     *
     * @param request
     * @return
     */
    @Override
    public UserInfo getLoginUser(HttpServletRequest request) {
        // 先判断是否已登录
        UserInfo userInfo = (UserInfo) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        ThrowUtils.throwIf(ObjectUtils.isEmpty(userInfo), ErrorCode.NOT_LOGIN_ERROR, "用户未登录");
        return this.getById(userInfo.getId());
    }

    /**
     * 获取脱敏的已登录用户信息
     *
     * @return
     */
    @Override
    public LoginUserInfoVO getLoginUserVO(UserInfo userInfo) {
        if (userInfo == null) {
            return null;
        }
        LoginUserInfoVO loginUserInfoVO = new LoginUserInfoVO();
        BeanUtils.copyProperties(userInfo, loginUserInfoVO);
        return loginUserInfoVO;
    }

    @Override
    public UserInfoVO getUserInfoVO(UserInfo user) {
        if (user == null) {
            return null;
        }
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(user, userInfoVO);
        return userInfoVO;
    }

    @Override
    public List<UserInfoVO> getUserInfoVO(List<UserInfo> userList) {
        if (CollectionUtils.isEmpty(userList)) {
            return new ArrayList<>();
        }
        return userList.stream().map(this::getUserInfoVO).collect(Collectors.toList());
    }

}




